package com.ontology.util.parser.content;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import com.ontology.util.OConstants;
import com.ontology.util.ODataType;
import com.ontology.util.OUtils;
import com.ontology.util.model.OCell;
import com.ontology.util.model.OColumn;
import com.ontology.util.model.ORow;
import com.ontology.util.model.impl.OntologyCell;
import com.ontology.util.model.impl.OntologyColumn;
import com.ontology.util.model.impl.OntologyRow;
import com.ontology.util.parser.OLineParser;
public abstract class AbstractLineParser<C> implements OLineParser<C> {
	private Set<String>	eligibleBlankValues	= new HashSet<String>();
	private String		delim;
	public String getDelim() {
		return delim == null ? "," : delim;
	}
	public void setDelim(String delim) {
		this.delim = delim;
	}
	public AbstractLineParser() {
		eligibleBlankValues.add(OConstants.ELIGIBLE_BLANK_A);
		eligibleBlankValues.add(OConstants.ELIGIBLE_BLANK_C);
		eligibleBlankValues.add(OConstants.ELIGIBLE_NULL_A);
		eligibleBlankValues.add(OConstants.ELIGIBLE_NULL_C);
	}
	public Set<String> getEligibleBlankValues() {
		return eligibleBlankValues;
	}
	public List<OColumn> parseHeaderLine(String content) {
		List<OColumn> oColumns = new ArrayList<OColumn>();
		List<String> columnTokens = OUtils.tokenizeString(content, "#");
		for (String columnToken : columnTokens) {
			OntologyColumn column = OUtils.buildColumn(columnToken);
			oColumns.add(column);
		}
		return oColumns;
	}
	public List<OColumn> parseHeaderLine(Row headerRow) {
		List<OColumn> columns = new ArrayList<OColumn>();
		int lastColumn = Math.max(headerRow.getLastCellNum(), 15);
		for (int cn = 0; cn < lastColumn; cn++) {
			Cell c = headerRow.getCell(cn, Row.RETURN_BLANK_AS_NULL);
			if (c == null) {
				// The spreadsheet is empty in this cell
				break;
			} else {
				// Do something useful with the cell's contents
				String columnName = c.getStringCellValue();
				columns.add(OUtils.buildColumn(columnName));
			}
		}
		return columns;
	}
	public ORow parseLineData(List<String> tokenizedLineData,
	List<OColumn> columns) {
		OntologyRow row = new OntologyRow();
		row.setColumnAndCellMap(new HashMap<OColumn, OCell<?>>());
		ListIterator<OColumn> iterateColumns = columns.listIterator();
		int colIndex = 0;
		while (iterateColumns.hasNext()) {
			colIndex = iterateColumns.nextIndex();
			OntologyColumn oColumn = (OntologyColumn) iterateColumns.next();
			String cellValue = StringUtils.trimToNull(getValueAgainstColumnIndex(tokenizedLineData, colIndex));
			if (cellValue == null
			|| getEligibleBlankValues().contains(cellValue)) {
				continue;
			}
			if (oColumn.getType() == null) {
				/* Column Type has not been analyzed yet */
				if (StringUtils.isNumeric(cellValue)) {
					oColumn.setType(ODataType.LONG);
					OntologyCell<Long> cell = new OntologyCell<Long>(Long.parseLong(cellValue, 10));
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
				Double doubleValue = OUtils.parseDouble(cellValue);
				if (doubleValue != null) {
					oColumn.setType(ODataType.DECIMAL);
					OntologyCell<Double> cell = new OntologyCell<Double>(doubleValue);
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
				Date parsedDate = OUtils.parseDate(cellValue);
				if (parsedDate != null) {
					oColumn.setType(ODataType.DATE);
					oColumn.setDateFormat(OConstants.DEFAULT_DATE_FORMAT);
					OntologyCell<Date> cell = new OntologyCell<Date>(parsedDate);
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
				/* Other wise make is type String */
				oColumn.setType(ODataType.STRING);
				OntologyCell<String> cell = new OntologyCell<String>(cellValue);
				row.getColumnAndCellMap().put(oColumn, cell);
				continue;
			} else {
				/* Column Type has been Analyzed */
				if (ODataType.LONG.equals(oColumn.getType())) {
					Long longValue = OUtils.parseLong(cellValue);
					OntologyCell<Long> cell = new OntologyCell<Long>(longValue);
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
				if (ODataType.DECIMAL.equals(oColumn.getType())) {
					Double doubleValue = OUtils.parseDouble(cellValue);
					OntologyCell<Double> cell = new OntologyCell<Double>(doubleValue);
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
				if (ODataType.DATE.equals(oColumn.getType())) {
					oColumn.setDateFormat(oColumn.getDateFormat() == null
					? OConstants.DEFAULT_DATE_FORMAT
					: oColumn.getDateFormat());
					OntologyCell<Date> cell = new OntologyCell<Date>(OUtils.parseDate(cellValue, oColumn.getDateFormat()));
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
				if (ODataType.STRING.equals(oColumn.getType())) {
					OntologyCell<String> cell = new OntologyCell<String>(cellValue);
					row.getColumnAndCellMap().put(oColumn, cell);
					continue;
				}
			}
		}
		return row;
	}
	protected String getValueAgainstColumnIndex(List<String> parsedData,
	Integer colIndex) {
		if (colIndex < parsedData.size()) {
			return parsedData.get(colIndex);
		}
		return null;
	}
}
